from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from apps.carts.seriazliers import (
    CartSerializer,
    SKUCartSerializer,
    CartDeleteSerializer,
    CartSelectedAllSerializer)
from django_redis import get_redis_connection

from apps.goods.models import SKU
from util.formatting import str_convert_bytes, bytes_convert_str


class CartView(APIView):
    """购物车增删改查"""

    def perform_authentication(self, request):
        """重写此方法 直接pass 可以延后认证 延后到第一次通过 request.user 或request.auth才去做认证"""
        pass

    def post(self, request):
        serializer = CartSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        sku_id = serializer.validated_data.get("sku_id")
        count = int(serializer.validated_data.get("count"))
        selected = serializer.validated_data.get("selected")
        try:
            user = request.user
        except:
            user = None
        response = Response(data=serializer.data, status=status.HTTP_201_CREATED)
        if user and user.is_authenticated:  # 检测是否匿名用户
            # 创建redis连接对象
            redis_conn = get_redis_connection("carts")
            pl = redis_conn.pipeline()  # 创建管道
            # 添加 如果添加到sku_id在hash中已经存在,需要做增量
            # redis_conn.hincrby('cart_%d % user.id, sku_id, count)
            # redis_conn.hincrby('cart_%d % user.id, sku_id_5, 3)
            # 如果要添加的sku_id在hash字典中不存在,就是新增,如果已存在,就会自动做增量计数再存储
            pl.hincrby("cart_%d" % user.id, sku_id, count)

            # 把勾选的商品sku_id 存储到set集合中
            if selected:  # 判断当前商品是否勾选,勾选的再向set集合中添加
                pl.sadd("selected_%d" % user.id, sku_id)
            # 执行管道
            pl.execute()
        else:
            cart_str = request.COOKIES.get("cart")
            if cart_str:
                cart_dict = str_convert_bytes(cart_str)
            else:
                cart_dict = {}
            if sku_id in cart_dict:
                cart_count = cart_dict[sku_id]["count"]
                count += int(cart_count)
            cart_dict[sku_id] = {"selected": selected, "count": count}
            cart_str = bytes_convert_str(cart_dict)
            response.set_cookie("cart", cart_str)
        return response

    def get(self, request):
        try:
            user = request.user
        except:
            user = None
        if user and user.is_authenticated:
            # 登录用户从redis中获取数据
            redis_conn = get_redis_connection("carts")
            cart_redis_dict = redis_conn.hgetall("cart_%d" % user.id)
            selected = redis_conn.smembers("selected_%d" % user.id)
            cart_dict = {}
            for sku_id_bytes, count_bytes in cart_redis_dict.items():
                cart_dict[int(sku_id_bytes)] = {
                    "count": int(count_bytes),
                    "selected": sku_id_bytes in selected,
                }
        else:
            cart_str = request.COOKIES.get("cart")
            if cart_str:
                cart_dict = str_convert_bytes(cart_str)
            else:
                return Response(status=status.HTTP_200_OK)
        sku_ids = cart_dict.keys()
        skus = SKU.objects.filter(id__in=sku_ids)
        for sku in skus:
            sku.count = cart_dict[sku.id]["count"]
            sku.selected = cart_dict[sku.id]["selected"]
        serializer = SKUCartSerializer(skus, many=True)
        return Response(serializer.data)

    def put(self, request):
        serializer = CartSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        sku_id = serializer.validated_data.get("sku_id")
        count = int(serializer.validated_data.get("count"))
        selected = serializer.validated_data.get("selected")
        response = Response(serializer.data)
        try:
            user = request.user
        except:
            user = None
        if user and user.is_authenticated:
            redis_conn = get_redis_connection("carts")
            # 创建管道对象
            pl = redis_conn.pipeline()
            # 覆盖sku_id 对应的count
            pl.hset("cart_%d" % user.id, sku_id, count)
            # 如果勾选就把勾选商品的sku_id存储到set集合
            if selected:
                pl.sadd("selected_%d" % user.id, sku_id)
            else:
                # 如果未勾选把就商品的sku_id从set集合中移除
                pl.srem("selected_%d" % user.id, sku_id)
            # 执行管道
            pl.execute()
        else:
            cart_bytes = request.COOKIES.get("cart")
            if cart_bytes:
                cart_dict = str_convert_bytes(cart_bytes)
            else:
                return Response(
                    {"message": "购物车获取异常"}, status=status.HTTP_400_BAD_REQUEST
                )
            cart_dict[sku_id] = {"count": count, "selected": selected}
            cart_str = bytes_convert_str(cart_dict)
            response.set_cookie("cart", cart_str)
        return response

    def delete(self, request):
        serializer = CartDeleteSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        sku_id = serializer.validated_data.get("sku_id")
        try:
            user = request.user
        except:
            user = None
        response = Response(status=status.HTTP_204_NO_CONTENT)
        if user:
            redis_conn = get_redis_connection("carts")
            pl = redis_conn.pipeline()
            pl.hdel("cart_%d" % user.id, sku_id)
            # 删除set数据
            pl.srem("selected_%d" % user.id, sku_id)
            pl.execute()
        else:
            cart_str = request.COOKIES.get("cart")
            if cart_str:
                cart_dict = str_convert_bytes(cart_str)
            else:
                return Response(
                    {"message": "cookie没有获取到"}, status=status.HTTP_400_BAD_REQUEST
                )
            if sku_id in cart_dict:
                del cart_dict[sku_id]
            if len(cart_dict.keys()):
                cart_str = bytes_convert_str(cart_dict)
                response.set_cookie("cart", cart_str)
            else:
                response.delete_cookie("cart")
        return response


class CartSelectedAllView(APIView):
    """购物车全选"""

    def perform_authentication(self, request):
        """重写此方法 直接pass 可以延后认证 延后到第一次通过 request.user 或request.auth才去做认证"""
        pass

    def put(self, request):
        serializer = CartSelectedAllSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        selected = serializer.validated_data.get("selected")
        response = Response(serializer.data)
        try:
            user = request.user.user
        except:
            user = None
        if user and user.is_authenticated:
            """登录用户操作redis数据"""
            # 创建redis连接对象
            redis_conn = get_redis_connection('cart')
            # 获取hash字典中的所有数据
            cart_redis_dict = redis_conn.hgetall('cart_%d' % user.id)
            # 把hash字典中的所有key
            sku_ids = cart_redis_dict.keys()
            # 判断当前selected是True还是False
            if selected:
                # 如果是True 就把所有sku_id 添加到set集合中 *[1, 2, 3]
                redis_conn.sadd('selected_%d' % user.id, *sku_ids)
            else:
                # 如果是False 就把所有sku_id 从set集合中删除
                redis_conn.srem('selected_%d' % user.id, *sku_ids)
        else:
            cart_str = request.COOKIES.get("cart")
            if cart_str:
                cart_dict = str_convert_bytes(cart_str)
            else:
                return Response({"message": "购物车内无数据"}, status=status.HTTP_400_BAD_REQUEST)
            for cart_id in cart_dict:
                cart_dict[cart_id]["selected"] = selected
            cart_str = bytes_convert_str(cart_dict)
            response.set_cookie("cart", cart_str)
        return response
